const std = @import("std");
const stdin = std.io.getStdIn();
const stdout = std.io.getStdOut().writer();
const expect = @import("std").testing.expect;

fn demo_general_purpose_allocator() !void {
    // 通用分配器
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const some_number = try allocator.create(u32);
    defer allocator.destroy(some_number);
    some_number.* = @as(u32, 100);
    try stdout.debug.print("Result: {d}!\n", .{some_number});
}

fn demo_page_allocator() !void {
    // page_allocator()在堆中分配整页内存的分配器。
    // 换句话说，每次使用 分配内存时page_allocator()，都会分配堆中的整页内存，而不是其中的一小部分。
    const allocator = std.heap.page_allocator;
    const memory = try allocator.alloc(u8, 5000);
    defer allocator.free(memory);
    try stdout.print("Result: memory.len  {d}!\n", .{memory.len});
}

fn demo_fixed_buffer_allocator() !void {
    // 固定大小的内存分配器
    // 超过分配的内存大小，则会给给出 OutOfMemory 的 error
    var buffer: [10]u8 = undefined;
    for (0..buffer.len) |i| {
        buffer[i] = 0; // Initialize to zero
    }
    var fba = std.heap.FixedBufferAllocator.init(&buffer);
    const allocator = fba.allocator();
    const input = try allocator.alloc(u8, 10);
    defer allocator.free(input);
    try stdout.print("Result: input.len {d}!\n", .{input.len});
}

fn demo() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    var input = try allocator.alloc(u8, 50);
    defer allocator.free(input);
    for (0..input.len) |i| {
        input[i] = 0; // initialize all fields to zero.
    }
    // 从标准输入中接收用户输入
    const input_reader = stdin.reader();
    _ = try input_reader.readUntilDelimiterOrEof(input, '\n');
    std.debug.print("{s}\n", .{input});
}

fn demo_aren() !void {
    // 它是一个分配器对象，允许您分配任意多次内存，但所有内存只能释放一次。
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    var aa = std.heap.ArenaAllocator.init(gpa.allocator());
    defer aa.deinit();
    const allocator = aa.allocator();

    const in1 = try allocator.alloc(u8, 5);
    const in2 = try allocator.alloc(u8, 10);
    const in3 = try allocator.alloc(u8, 15);
    _ = in1;
    _ = in2;
    _ = in3;
    try stdout.print("{s}\n", .{"ArenaAllocator"});
}

const User = struct {
    id: usize,
    name: []const u8,

    pub fn init(id: usize, name: []const u8) User {
        return .{ .id = id, .name = name };
    }
};

fn demo_struct() !void {
    // 分配一块内存，存放结构体
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const user = try allocator.create(User);
    defer allocator.destroy(user);
    user.* = User.init(0, "fhj");
    try stdout.print("Result: {s}!\n", .{"demo_struct"});
}

pub fn main() !void {
    try stdout.print("Result: {s}!\n", .{"hello world"});
    // ############################
    try demo_page_allocator();
    try demo_fixed_buffer_allocator();
    // try demo();
    try demo_aren();
    try demo_struct();
    // ############################
}

test "test main" {
    const n = 8;
    try stdout.print("Result: {d}!\n", .{n});
}
